home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / dependantscan / source / dependantscan.c < prev    next >
C/C++ Source or Header  |  1995-11-14  |  18KB  |  371 lines

  1. #define DEF_DEPENDANTSCAN_C
  2.  
  3. #include <exec/types.h>
  4. #include <exec/memory.h>
  5. #include <utility/tagitem.h>
  6. #include <dos/dosasl.h>
  7. #include <proto/icon.h>
  8. #include <clib/dos_protos.h>
  9. #include <clib/exec_protos.h>
  10.  
  11. #include <stdio.h>
  12. #include <string.h>
  13.  
  14. #include "ProcessDirectory.h"
  15. #include "DependantScan.h"
  16. #include "RequesterError.h"
  17.  
  18. char *DPSArgument[DPS_ARG_COUNT];                              /* arguments parsed from the command line or our icon */
  19. char DPSParsedPattern[255];                                                /* the file pattern we are matching */
  20. int FilesOnLine;                                               /* number of files mentioned on the current line */
  21. FILE *OutputStream = NULL;                                     /* the file we are writing to */
  22.  
  23. /*
  24.     char *wrap_files(
  25.         char *in_between)                                                        what we are putting between files
  26.  
  27.    * Description
  28.        This function will continue the make file on the next line if there are too many files on the current line.
  29. */
  30. char *wrap_files(
  31.     char *in_between)                                                            /* what we are putting between files */
  32. {
  33.     if (FilesOnLine++ == *(LONG *)DPSArgument[DPS_ARG_FILESONLINE])                              /* if this is the last file to be printed on this line */
  34.     {
  35.         if (!strcmp(in_between," "))                                        /* if we are building the project dependency list */
  36.          fprintf(OutputStream,"\\\n");                                    /* then, this is how to continue the line */
  37.       else if (!strcmp(in_between," + "))                                /* if we are building the link object list */
  38.           fprintf(OutputStream," +\\\n");                                /* continue the line this way */
  39.       else                                                                        /* we don't know what we are doing */
  40.             fprintf(OutputStream,"%s\\\n",in_between);            /* continue the line in a generic way */
  41.  
  42.         in_between = "";                                                        /* put the next file at the beginning of the next line */
  43.         FilesOnLine = 1;                                         /* reset the counter */
  44.    }
  45.  
  46.    return (in_between);                                                        /* tell caller to use this before the next file */
  47. }
  48.  
  49. /*
  50.     int dpscan_pass1(
  51.         struct AnchorPath *anchor,                                            file being processed
  52.         char *path,                                                                the pathname (including trailing slash) that 'fib' resides in
  53.         char *in_between)                                                        what to put between each file
  54.  
  55.    * Description
  56.        This function is used to build the project dependancy list and link object file list. It is designed to be called by
  57.        process_directory(). The only difference in these two parts is what is placed between each file. The 'in_between' argument is used for
  58.        this purpose.
  59.  
  60.         Note: This routine uses FilesOnLine and therefore, that value must be properly setup before this routine is called.
  61. */
  62. int dpscan_pass1(
  63.     struct AnchorPath *anchor,                                                /* file being processed */
  64.     char *in_between)                                                            /* what to put between each file */
  65. {
  66.     if (MatchPatternNoCase(DPSParsedPattern,anchor->ap_Info.fib_FileName))                       /* if this filename matches */
  67.     {
  68.         in_between = wrap_files(in_between);                     /* possibly move to the next line */
  69.  
  70.         if (strrchr(anchor->ap_Info.fib_FileName,'.'))           /* if the filename has an extension */
  71.         {
  72.             *strrchr(anchor->ap_Info.fib_FileName,'.') = '\0';    /* chop off the name at it's extension */
  73.           fprintf(OutputStream,"%s$(obj)%s.o",in_between,anchor->ap_Info.fib_FileName);          /* put the current file into the make file */
  74.           anchor->ap_Info.fib_FileName[strlen(anchor->ap_Info.fib_FileName)] = '.';              /* restore the file's extension */
  75.       }
  76.       else                                                                        /* the filename has no extension */
  77.       {
  78.           fprintf(OutputStream,"%s$(obj)%s.o",in_between,anchor->ap_Info.fib_FileName);          /* use the filename as-is */
  79.       }
  80.     }
  81.  
  82.     if (*in_between && DPSArgument[DPS_ARG_VERBOSE])            /* if we should print stuff */
  83.         printf(dps_locale_string(DPS_MSG_PASS1_PROGRESS));
  84.  
  85.     return (0);
  86. }
  87.  
  88. /*
  89.     int dpscan_pass2(
  90.         struct AnchorPath *anchor,                                            file being processed
  91.         void *_not_used)                                                        currently unused argument
  92.  
  93.    * Description
  94.        This routine is designed to be called by process_directory(). It builds the dependancy list for the source modules in the make file.
  95.        This function assumes that DPSParsedPattern has been created.
  96. */
  97. int dpscan_pass2(
  98.     struct AnchorPath *anchor,                                                /* file being processed */
  99.     void *_not_used)                                                            /* currently unused argument */
  100. {
  101.     FILE *input_stream = NULL;                                  /* connected to the file we are scanning for dependants */
  102.     char temp_str[DPS_LINE_BUFFER_SIZE];                                /* for buffering lines of the #include file */
  103.     char *include_name;                                                        /* points to the file being included (a portion of 'temp_str') */
  104.     int retval = 0;                                             /* 0 = good, other = bad */
  105.  
  106.     if (MatchPatternNoCase(DPSParsedPattern,anchor->ap_Info.fib_FileName) == FALSE)              /* if this filename does not match */
  107.         goto _ABORT;
  108.  
  109.     fprintf(OutputStream,"\n\n");                               /* setup for the new target */
  110.  
  111.     FilesOnLine = 0;                                            /* setup for call to dpscan_pass1() */
  112.     dpscan_pass1(anchor,"");                                    /* put the object file for this bit of source code at the start of the line */
  113.  
  114.     fprintf(OutputStream,": %s",anchor->ap_Buf);                /* put the file itself as a dependant into the makefile */
  115.  
  116.     if (DPSArgument[DPS_ARG_VERBOSE])                           /* if we should print stuff */
  117.         printf(dps_locale_string(DPS_MSG_PASS2_FILE),anchor->ap_Buf);                             /* show user which file we are processing what is happening */
  118.  
  119.     if ((input_stream = fopen(anchor->ap_Info.fib_FileName,"r")) == NULL)                        /* if we cannot open the file */
  120.     {
  121.         quick_requester_error(retval = DPS_ERROR_CANNOT_OPEN_FILE,DPS_ERROR_CANNOT_OPEN_FILE,anchor->ap_Info.fib_FileName);
  122.         goto _ABORT;
  123.     }
  124.  
  125.     while (fgets(temp_str,sizeof(temp_str),input_stream))       /* while we can get a line from the file */
  126.     {
  127.         if ((include_name = strstr(temp_str,"#include")) != NULL)                                 /* if this line includes something */
  128.         {
  129.             if ((include_name = strchr(include_name,'\"')) != NULL)                                            /* if it is the type of #include that has quotes */
  130.             {
  131.                 ++include_name;                                                /* skip the opening quote */
  132.  
  133.                 if (strchr(include_name,'\"'))                            /* if there is a second quote on this line */
  134.                 {
  135.                     *strchr(include_name,'\"') = '\0';              /* cut off the name at the second quote */
  136.  
  137.                     fprintf(OutputStream,"%s",wrap_files(" "));        /* separate this file from previous ones */
  138.  
  139. /* put the path of this #include file into the makefile */
  140.                     if (strrchr(anchor->ap_Buf,'/'))                    /* if the full name has a slash in it */
  141.                         fprintf(OutputStream,"%.*s",1 + (strrchr(anchor->ap_Buf,'/') - anchor->ap_Buf), anchor->ap_Buf);
  142.                   else if (strrchr(anchor->ap_Buf,':'))            /* if the full name has a drive in it */
  143.                             fprintf(OutputStream,"%.*s",1 + (strrchr(anchor->ap_Buf,':') - anchor->ap_Buf), anchor->ap_Buf);
  144.  
  145.                     fprintf(OutputStream,"%s",include_name);            /* put the #include file into the makefile */
  146.  
  147.                     if (DPSArgument[DPS_ARG_VERBOSE])               /* if we should print stuff */
  148.                         printf(dps_locale_string(DPS_MSG_PASS2_PROGRESS));                            /* show user what is happening */
  149.                 }
  150.             }
  151.         }
  152.         else if (strchr(temp_str,'{'))                                    /* if this line is after the #include's */
  153.         {
  154.             break;                                                                /* then, we are finished */
  155.         }
  156.     }
  157.  
  158.     if (strrchr(anchor->ap_Info.fib_FileName,'.'))              /* if the filename has a period in it */
  159.         fprintf(OutputStream,"\n\t$(CC) $*%s",strrchr(anchor->ap_Info.fib_FileName,'.'));         /* tell the compiler how to compile this project */
  160.    else                                                        /* no period in the file name */
  161.         fprintf(OutputStream,"\n\t$(CC) $*");                    /* use default compilation???? */
  162.  
  163.     if (DPSArgument[DPS_ARG_VERBOSE])                           /* if we should print stuff */
  164.         printf(dps_locale_string(DPS_MSG_PASS2_SEPARATOR));      /* show user what is happening */
  165.  
  166. _ABORT:
  167.     if (input_stream)                                                            /* if we have a file open */
  168.         fclose(input_stream);                                                /* then, clean up after ourselves */
  169.  
  170.     return (retval);
  171. }
  172.  
  173. /*
  174.     int dps_build_path(
  175.         char *destination,                                                    the resulting pathname may be stored here
  176.         char *source)                                                            the source pathname
  177.  
  178.    * Description
  179.        If possible, this function will combine DPSArgument[DPS_ARG_PATH] with 'source' and store the result at 'destination'.
  180.  
  181.    * Return Value
  182.        0 = could not combine the paths
  183.        1 = paths combined
  184. */
  185. int dps_build_path(
  186.     char *destination,                                                        /* the resulting pathname may be stored here */
  187.     char *source)                                                                /* the source pathname */
  188. {
  189.     char last_char;                                                            /* the last character in 'source' */
  190.  
  191.     if (!strchr(source,':') && (source[0] != '/'))                    /* if the source pathname does not have a directory specifier in it */
  192.     {
  193.         strcpy(destination,DPSArgument[DPS_ARG_PATH]);                /* start with the path for our operations */
  194.  
  195.         last_char = destination[strlen(destination)-1];                /* get the last character for examination */
  196.  
  197.         if ((last_char != ':') && (last_char != '/'))                /* if a directory separator is needed */
  198.             strcat(destination,"/");                                        /* put the directory separator */
  199.  
  200.       strcat(destination,source);                                        /* create the remainder of the path */
  201.  
  202.       return (1);                                                                /* let caller know that we could do it */
  203.     }
  204.  
  205.     return (0);                                                                    /* we didn't do it */
  206. }
  207.  
  208. /*
  209.     int dps_include_rules(
  210.         char *filename)                                                        the name of the rules file to be included
  211.  
  212.    * Description
  213.        This function attempts to write the file specified by 'filename' to OutputStream (the makefile).
  214.  
  215.    * Return Value
  216.        0 = OK
  217.        other = bad
  218. */
  219. int dps_include_rules(
  220.     char *filename)                                                            /* the name of the rules file to be included */
  221. {
  222.     int retval = 0;                                             /* another value is bad */
  223.     FILE *stream;                                                                /* connected to the rules file */
  224.     char *line_buffer = NULL;                                                /* for buffering the input file */
  225.     size_t bytes_read;                                                        /* the number of bytes read on each pass */
  226.  
  227.     if (DPSArgument[DPS_ARG_VERBOSE])                                    /* if we should say what is happening */
  228.        printf(dps_locale_string(DPS_MSG_INCLUDING_RULES),filename);
  229.  
  230.    if ((stream = fopen(filename,"r")) == NULL)                        /* if we cannot open the file */
  231. /* then, we are done */
  232.        {quick_requester_error(retval = DPS_ERROR_CANNOT_OPEN_FILE,DPS_ERROR_CANNOT_OPEN_FILE,filename); goto _ABORT;}
  233.  
  234.     if ((line_buffer = AllocVec(DPS_LINE_BUFFER_SIZE,0)) == NULL)                                /* if we cannot get some memory for our buffer */
  235.         {quick_requester_error(retval = DPS_ERROR_CANNOT_ALLOCATE,DPS_ERROR_CANNOT_ALLOCATE,DPS_LINE_BUFFER_SIZE); goto _ABORT;}
  236.  
  237.    while (!feof(stream) && !ferror(stream))                            /* while we are not at the end of the file and there is no error with the file */
  238.    {
  239.        if ((bytes_read = fread(line_buffer,1,DPS_LINE_BUFFER_SIZE,stream)) == 0)                 /* if we have no more bytes to read */
  240.            break;
  241.  
  242.       if (fwrite(line_buffer,1,bytes_read,OutputStream) != bytes_read)                          /* if we cannot write some bytes */
  243.           {quick_requester_error(retval = DPS_ERROR_CANNOT_WRITE_FILE,DPS_ERROR_CANNOT_WRITE_FILE,bytes_read,filename); goto _ABORT;}
  244.    }
  245.  
  246. _ABORT:
  247.     if (stream)                                                                    /* if we have a file open */
  248.         fclose(stream);                                                        /* clean up after ourselves */
  249.  
  250.    return (retval);                                                            /* non-zero is bad */
  251. }
  252.  
  253. /*
  254.     int dependant_scan(void)
  255.  
  256.     * Description
  257.         This function makes a makefile with the currently parsed arguments (mostly).
  258. */
  259. int dependant_scan(void)
  260. {
  261.     char object_dir_path[PD_PATHMAX];                                    /* if needed, the new value for DPSArgument[DPS_ARG_OBJECT_DIR] */
  262.     int retval = 0;                                             /* other than this value is bad */
  263.  
  264.    if (DPSArgument[DPS_ARG_PATH])                                        /* if we are scanning a different directory */
  265.    {
  266.         if (dps_build_path(object_dir_path,DPSArgument[DPS_ARG_OBJECT_DIR]))                      /* if the object directory can be expanded */
  267.            DPSArgument[DPS_ARG_OBJECT_DIR] = object_dir_path;    /* then, use the fully-qualified path */
  268.     }
  269.  
  270.     if (DPSArgument[DPS_ARG_VERBOSE])                                    /* if we should say what is happening */
  271.         printf(dps_locale_string(DPS_MSG_CREATING_SMAKEFILE),DPSArgument[DPS_ARG_MAKEFILE]);
  272.  
  273.     if ((OutputStream = fopen(DPSArgument[DPS_ARG_MAKEFILE],"w")) == NULL)                       /* if we cannot open the output file */
  274.         {quick_requester_error(retval = DPS_ERROR_CANNOT_OPEN_FILE,DPS_ERROR_CANNOT_OPEN_FILE,DPSArgument[DPS_ARG_MAKEFILE]); goto _ABORT;}
  275.  
  276.     if (DPSArgument[DPS_ARG_RULES])                                        /* if we should include a "rules" file at the top of the makefile */
  277.     {
  278.       if ((retval = dps_include_rules(DPSArgument[DPS_ARG_RULES])) != 0)                                /* if we have difficulty including the rules file */
  279.           goto _ABORT;
  280.     }
  281.  
  282.      ParsePatternNoCase(DPSArgument[DPS_ARG_MATCH],DPSParsedPattern,sizeof(DPSParsedPattern));    /* convert the file pattern into something useful */
  283.  
  284. /* create the first part of the first couple of lines */
  285.    fprintf(OutputStream,"obj = %s\n\n%s:",DPSArgument[DPS_ARG_OBJECT_DIR],DPSArgument[DPS_ARG_PROJECT]);
  286.     FilesOnLine = 1;                                                            /* only one file on this line */
  287.  
  288.     if (DPSArgument[DPS_ARG_VERBOSE])                           /* if we should print stuff */
  289.         printf(dps_locale_string(DPS_MSG_PASS1_BEGINNING));
  290.  
  291. /* if we cannot perform the first pass */
  292.     if (process_directory(DPSArgument[DPS_ARG_PATH],"#?",dpscan_pass1,process_directory_do_nothing," "))
  293.         {quick_requester_error(retval = DPS_ERROR_PASS_UNSUCCESSFUL,DPS_ERROR_PASS_UNSUCCESSFUL,1); goto _ABORT;}
  294.  
  295.    fprintf(OutputStream,"\n\t$(LD) <WITH <\nFrom %s",DPSArgument[DPS_ARG_FROM]);                /* setup the link part */
  296.     FilesOnLine = 1;                                            /* only one file on this line */
  297.  
  298.     if (DPSArgument[DPS_ARG_VERBOSE])                           /* if we should print stuff */
  299.         printf(dps_locale_string(DPS_MSG_BUILDING_LINK_LIST));
  300.  
  301. /* if we cannot perform the second pass */
  302.     if (process_directory(DPSArgument[DPS_ARG_PATH],"#?",dpscan_pass1,process_directory_do_nothing," + "))
  303.         {quick_requester_error(retval = DPS_ERROR_PASS_UNSUCCESSFUL,DPS_ERROR_PASS_UNSUCCESSFUL,2); goto _ABORT;}
  304.  
  305.     if (DPSArgument[DPS_ARG_VERBOSE])                           /* if we are printing stuff */
  306.         printf(dps_locale_string(DPS_MSG_PASS2_BEGINNING));
  307.  
  308.    fprintf(OutputStream,"\n\nTo %s\nLibrary %s\n<",DPSArgument[DPS_ARG_PROJECT],DPSArgument[DPS_ARG_LIBRARY]);
  309.  
  310.     if (process_directory(DPSArgument[DPS_ARG_PATH],"#?",dpscan_pass2,process_directory_do_nothing,NULL))
  311.         {quick_requester_error(retval = DPS_ERROR_PASS_UNSUCCESSFUL,DPS_ERROR_PASS_UNSUCCESSFUL,3); goto _ABORT;}
  312.  
  313. _ABORT:
  314.    if (OutputStream)                                           /* if we have a file open */
  315.    {
  316.        if (DPSArgument[DPS_ARG_VERBOSE])                        /* if we should say what is happening */
  317.             printf(dps_locale_string(DPS_MSG_CLOSING_SMAKEFILE),DPSArgument[DPS_ARG_MAKEFILE]);
  318.  
  319.         fclose(OutputStream);                                                /* then, close it */
  320.        OutputStream = NULL;                                                    /* note that it is closed */
  321.    }
  322.  
  323.     return (retval);                                                            /* let caller know what happened */
  324. }
  325.  
  326. int main(
  327.     int argc,
  328.     char *argv)
  329. {
  330.    struct RDArgs *rdargs = NULL;                               /* for parsing the command line */
  331.    BOOL free_args_needed = FALSE;                              /* true when we should call FreeArgs() */
  332.    int retval = 0;
  333.  
  334.    requester_error_set_defaults(NULL,dps_locale_string(DPS_MSG_DEPENDANTSCAN_ERROR),dps_locale_string,dps_locale_string(DPS_MSG_DARN));
  335.  
  336.     if (argc)                                                                    /* if we were started from the shell */
  337.     {
  338.        if ((rdargs = (struct RDArgs *)AllocDosObject(DOS_RDARGS,TAG_DONE)) == NULL)              /* if we cannot get some memory for this DOS structure */
  339.            {quick_requester_error(retval = DPS_ERROR_ALLOCDOSOBJECT,DPS_ERROR_ALLOCDOSOBJECT); goto _ABORT;}
  340.  
  341.        if ((free_args_needed = dps_get_shell_arguments(rdargs)) == FALSE)                        /* if we have an error while getting the command line arguments */
  342.        {
  343.            PrintFault(IoErr(),dps_locale_string(DPS_MSG_DEPENDANTSCAN));                          /* tell the user what went wrong */
  344.          retval = DPS_ERROR_PASS_UNSUCCESSFUL;
  345.          goto _ABORT;
  346.       }
  347.  
  348.       retval = dependant_scan();                                            /* actually do the scanning */
  349.    }
  350.    else                                                                            /* must have been started from the WB */
  351.    {
  352.        retval = dps_process_workbench_arguments((struct WBStartup *)argv);                       /* parse the workbench arguments */
  353.    }
  354.  
  355. _ABORT:
  356.     if (retval == 0)                                            /* if this was a successful run */
  357.     {
  358.         if (DPSArgument[DPS_ARG_VERBOSE])                                /* if we are notifying the user */
  359. /* notify the user of the successful run */
  360.          requester_error(NULL,dps_locale_string(DPS_MSG_DEPENDANTSCAN_MSG),NULL,dps_locale_string(DPS_MSG_COOL),DPS_MSG_SUCCESSFUL,DPSArgument[DPS_ARG_MAKEFILE],DPSArgument[DPS_ARG_PROJECT]);
  361.     }
  362.  
  363.     if (free_args_needed)                                       /* if we need to free any arguments allocated by DOS */
  364.         FreeArgs(rdargs);                                                        /* then, we don't need them anymore */
  365.  
  366.    if (rdargs)                                                                    /* if we allocated this */
  367.        FreeDosObject(DOS_RDARGS,rdargs);                                /* then, free it */
  368.  
  369.    return (retval);
  370. }
  371.